﻿using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using CDA = System.ComponentModel.DataAnnotations;
using System.Data;
using System.Data.SqlClient;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Linq;
using System.Linq.Dynamic;
using System.Linq.Expressions;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;
using System.Web;
using System.Web.DynamicData;
using SWD = System.Web.DynamicData;
using System.Web.UI.WebControls;
using Dimok;

namespace Data.LINQ {
	#region TableExtensions

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>	Exception for signalling no table errors. </summary>
	///
	/// <remarks>	Dimon, 12/21/2010. </remarks>
	////////////////////////////////////////////////////////////////////////////////////////////////////

	public class NoTableException : Exception { }

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>	Exception for signalling no column errors. </summary>
	///
	/// <remarks>	Dimon, 12/21/2010. </remarks>
	////////////////////////////////////////////////////////////////////////////////////////////////////

	public class NoColumnException : Exception {
		public NoColumnException(string TableName, string ColumnName) : base("There is no [" + ColumnName + "] in [" + TableName + "].") { }
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>	Table extensions. </summary>
	///
	/// <remarks>	Dimon, 12/21/2010. </remarks>
	////////////////////////////////////////////////////////////////////////////////////////////////////

	public static class TableExtensions {

		#region DataContext

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A DataContext extension method that gets a update table. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="context">		The context to act on. </param>
		/// <param name="TableName">	Name of the table. </param>
		///
		/// <returns>	The update table. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static ITable GetUpdateTable(this DataContext context, string TableName) {
			return context.FinfActionTable<UpdateTableAttribute, InsertTableAttribute, DeleteTableAttribute>(TableName, true);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A DataContext extension method that gets an insert table. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="context">		The context to act on. </param>
		/// <param name="TableName">	Name of the table. </param>
		///
		/// <returns>	The insert table. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static ITable GetInsertTable(this DataContext context, string TableName) {
			return context.FinfActionTable<InsertTableAttribute, DeleteTableAttribute, UpdateTableAttribute>(TableName, true);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A DataContext extension method that gets a delete table. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="context">		The context to act on. </param>
		/// <param name="TableName">	Name of the table. </param>
		///
		/// <returns>	The delete table. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static ITable GetDeleteTable(this DataContext context, string TableName) {
			return context.FinfActionTable<DeleteTableAttribute, InsertTableAttribute, UpdateTableAttribute>(TableName, true);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A DataContext extension method that finf action table. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <exception cref="TypeLoadException">	Thrown when typeload. </exception>
		///
		/// <typeparam name="TAttribute1">	Type of the attribute 1. </typeparam>
		/// <typeparam name="TAttribute2">	Type of the attribute 2. </typeparam>
		/// <typeparam name="TAttribute3">	Type of the attribute 3. </typeparam>
		/// <param name="context">				The context to act on. </param>
		/// <param name="TableName">			Name of the table. </param>
		/// <param name="SelfAsDefault">	true to self as default. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		private static ITable FinfActionTable<TAttribute1, TAttribute2, TAttribute3>(this DataContext context, string TableName, bool SelfAsDefault)
			where TAttribute1 : ActionTableAttribute
			where TAttribute2 : ActionTableAttribute
			where TAttribute3 : ActionTableAttribute {
			if (!context.HasActionTableType<TAttribute1>(TableName)) return null;
			Type t = SWD.MetaModel.GetModel(context.GetType()).FindActionTableType<TAttribute1, TAttribute2, TAttribute3>(TableName, SelfAsDefault);
			if (t == null) throw new TypeLoadException("Entity " + TableName + " is not found in " + context.GetType().Name);
			return context.GetTable(t);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A DataContext extension method that gets an action table. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <typeparam name="TAttribute">	Type of the attribute. </typeparam>
		/// <param name="context">				The context to act on. </param>
		/// <param name="TableName">			Name of the table. </param>
		/// <param name="SelfAsDefault">	true to self as default. </param>
		///
		/// <returns>	The action table< t attribute> </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		private static ITable GetActionTable<TAttribute>(this DataContext context, string TableName, bool SelfAsDefault) where TAttribute : ActionTableAttribute {
			return context.GetTable(SWD.MetaModel.GetModel(context.GetType()).GetActionTableType<TAttribute>(TableName, SelfAsDefault));
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A DataContext extension method that query if 'context' has action table type. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <typeparam name="TAttribute">	Type of the attribute. </typeparam>
		/// <param name="context">		The context to act on. </param>
		/// <param name="EntityName">	Name of the entity. </param>
		///
		/// <returns>	true if action table type< t attribute>, false if not. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		private static bool HasActionTableType<TAttribute>(this DataContext context, string EntityName) where TAttribute : ActionTableAttribute {
			return SWD.MetaModel.GetModel(context.GetType()).HasActionTableType<TAttribute>(EntityName);
		}
		#endregion

		#region MetaModel

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A SWD.MetaModel extension method that gets a default filter. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="MetaModel">	The meta model. </param>
		/// <param name="EntityType">	Type of the entity. </param>
		///
		/// <returns>	The default filter. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static string GetDefaultFilter(this SWD.MetaModel MetaModel, Type EntityType) {
			return MotoBank.MetaModel.GetTable(EntityType).Attributes.OfType<SelectTableAttribute>()
				.Select(a => a.DefaultFilter).SingleOrDefault() + "";
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A SWD.MetaModel extension method that gets a column. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="MetaModel">	The meta model. </param>
		/// <param name="TEntity">		The entity. </param>
		/// <param name="ColumnName">	Name of the column. </param>
		///
		/// <returns>	The column. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static MetaColumn GetColumn(this SWD.MetaModel MetaModel,Type TEntity,string ColumnName) {
			ColumnName = ColumnName.ToLower();
			return MotoBank.MetaModel.GetTable(TEntity).Columns.Where(c => c.Name.ToLower() == ColumnName).SingleOrDefault();
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Enumerates get columns in this collection. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <typeparam name="TAttribute">	Type of the attribute. </typeparam>
		/// <param name="MetaModel">	The meta model. </param>
		/// <param name="EntityType">	Type of the entity. </param>
		///
		/// <returns>	
		/// An enumerator that allows foreach to be used to process get columns< t attribute> in this
		/// collection. 
		/// </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static IEnumerable<MetaColumn> GetColumns<TAttribute>(this SWD.MetaModel MetaModel, Type EntityType) where TAttribute : Attribute {
			return MotoBank.MetaModel.GetTable(EntityType).Columns.Where(c => c.Attributes.OfType<TAttribute>().Count() > 0);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A SWD.MetaModel extension method that gets a look up fields. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="MetaModel">	The meta model. </param>
		/// <param name="EntityType">	Type of the entity. </param>
		///
		/// <returns>	The look up fields. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static string[] GetLookUpFields(this SWD.MetaModel MetaModel, Type EntityType) {
			return MetaModel.GetTable(EntityType).Columns
				.Select(c => c.Attributes.OfType<EditColumnTemplateAttribute>().SingleOrDefault())
				.Where(e => e!=null && (e.LookUpFieldName+"") != "").Select(n => n.LookUpFieldName).ToArray();
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A SWD.MetaModel extension method that gets an ordered fields. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <typeparam name="TAttribute">	Type of the attribute. </typeparam>
		/// <param name="MetaModel">	The meta model. </param>
		/// <param name="EntityType">	Type of the entity. </param>
		///
		/// <returns>	The ordered fields< t attribute> </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static string[] GetOrderedFields<TAttribute>(this SWD.MetaModel MetaModel, Type EntityType) where TAttribute : OrderedFieldAttribute {
			return MetaModel.GetTable(EntityType).Columns
				.Select(c => c.Attributes.OfType<TAttribute>().Select(a => new { Name = c.Name, Index = a.Index }).SingleOrDefault())
				.Where(n => n != null).OrderBy(n => n.Index).Select(n => n.Name).ToArray();
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A SWD.MetaModel extension method that gets a sort fields. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="MetaModel">	The meta model. </param>
		/// <param name="EntityType">	Type of the entity. </param>
		///
		/// <returns>	The sort fields. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static string[] GetSortFields(this SWD.MetaModel MetaModel, Type EntityType) {
			return MetaModel.GetTable(EntityType).Columns
				.Select(c => c.Attributes.OfType<SortFieldAttribute>().Select(a => new { Name = c.Name, Index = a.Index, Dir = ((int)a.Direction + 1) }).SingleOrDefault())
				.Where(n => n != null).OrderBy(n => n.Index).Select(n => n.Name + "|" + n.Dir).ToArray();
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A SWD.MetaModel extension method that gets a sort fields dictionary. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="MetaModel">	The meta model. </param>
		/// <param name="EntityType">	Type of the entity. </param>
		///
		/// <returns>	The sort fields dictionary. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static Dictionary<string, int> GetSortFieldsDict(this SWD.MetaModel MetaModel, Type EntityType) {
			return MetaModel.GetTable(EntityType).Columns
				.Select(c => c.Attributes.OfType<SortFieldAttribute>()
								.Select(a => new { Name = c.Name, Index = a.Index, Direction = ((int)a.Direction + 1) }).SingleOrDefault())
				.Where(n => n != null).OrderBy(n => n.Index).ToDictionary(n => n.Name, n => n.Direction);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A DataContext extension method that query if 'context' has action table type. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <typeparam name="TAttribute">	Type of the attribute. </typeparam>
		/// <param name="MetaModel">	The meta model. </param>
		/// <param name="EntityName">	Name of the entity. </param>
		///
		/// <returns>	true if action table type< t attribute>, false if not. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		private static bool HasActionTableType<TAttribute>(this SWD.MetaModel MetaModel, string EntityName) where TAttribute : ActionTableAttribute {
			return MetaModel.HasActionTableType<TAttribute>(MetaModel.GetEntityType(EntityName, true));
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A DataContext extension method that query if 'context' has action table type. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <typeparam name="TAttribute">	Type of the attribute. </typeparam>
		/// <param name="MetaModel">	The meta model. </param>
		/// <param name="EntityType">	Type of the entity. </param>
		///
		/// <returns>	true if action table type< t attribute>, false if not. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		private static bool HasActionTableType<TAttribute>(this SWD.MetaModel MetaModel, Type EntityType) where TAttribute : ActionTableAttribute {
			return MetaModel.GetTable(EntityType).Attributes.OfType<TAttribute>().Count() > 0;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A SWD.MetaModel extension method that gets an action table attribute. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="MetaModel">								The meta model. </param>
		/// <param name="EntityType">								Type of the entity. </param>
		/// <param name="ActionTableAttributeType">	Type of the action table attribute. </param>
		///
		/// <returns>	The action table attribute. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		private static ActionTableAttribute GetActionTableAttribute(this SWD.MetaModel MetaModel, Type EntityType, Type ActionTableAttributeType) {
			return MetaModel.GetTable(EntityType).Attributes.Cast<object>()
				.Where(o => ActionTableAttributeType.IsInstanceOfType(o)).SingleOrDefault() as ActionTableAttribute;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A SWD.MetaModel extension method that queries if we can update 'MetaModel'. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="MetaModel">	The meta model. </param>
		/// <param name="EntityType">	Type of the entity. </param>
		///
		/// <returns>	true if it succeeds, false if it fails. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static bool CanUpdate(this SWD.MetaModel MetaModel, Type EntityType) {
			return MetaModel.HasActionTableType<UpdateTableAttribute>(EntityType);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A SWD.MetaModel extension method that queries if we can delete 'MetaModel'. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="MetaModel">	The meta model. </param>
		/// <param name="EntityType">	Type of the entity. </param>
		///
		/// <returns>	true if it succeeds, false if it fails. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static bool CanDelete(this SWD.MetaModel MetaModel, Type EntityType) {
			return MetaModel.HasActionTableType<DeleteTableAttribute>(EntityType);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A SWD.MetaModel extension method that queries if we can insert 'MetaModel'. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="MetaModel">	The meta model. </param>
		/// <param name="EntityType">	Type of the entity. </param>
		///
		/// <returns>	true if it succeeds, false if it fails. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static bool CanInsert(this SWD.MetaModel MetaModel, Type EntityType) {
			return MetaModel.HasActionTableType<InsertTableAttribute>(EntityType);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A SWD.MetaModel extension method that gets a detail key names. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="MetaModel">	The meta model. </param>
		/// <param name="EntityType">	Type of the entity. </param>
		///
		/// <returns>	The detail key names. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static string[] GetDetailKeyNames(this SWD.MetaModel MetaModel, Type EntityType) {
			var keyNames = MotoBank.MetaModel.GetTable(EntityType).Columns
			  .Select(c => c.Attributes.OfType<DetailKeyAttribute>().Select(a => c.Name).SingleOrDefault())
			  .Where(s => s + "" != "").ToArray();
			return keyNames.Length > 0 ? keyNames : MetaModel.GetClientKeyNames(EntityType);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A SWD.MetaModel extension method that gets a client key names. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="MetaModel">	The meta model. </param>
		/// <param name="EntityType">	Type of the entity. </param>
		///
		/// <returns>	The client key names. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static string[] GetClientKeyNames(this SWD.MetaModel MetaModel, Type EntityType) {
			var keyNames = MetaModel.GetTable(EntityType).Columns
				.Select(c => c.Attributes.OfType<ClientKeyAttribute>().Select(a => c.Name).SingleOrDefault())
				.Where(s => s + "" != "").ToArray();
			return keyNames.Length > 0 ? keyNames : MetaModel.GetPKNames(EntityType);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A SWD.MetaModel extension method that gets a pk names. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="MetaModel">	The meta model. </param>
		/// <param name="EntityType">	Type of the entity. </param>
		///
		/// <returns>	The pk names. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static string[] GetPKNames(this SWD.MetaModel MetaModel, Type EntityType) {
			return MetaModel.GetTable(EntityType).Columns.Where(c => c.IsPrimaryKey).Select(c => c.Name).ToArray();
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A SWD.MetaModel extension method that gets a meta column. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="MetaModel">	The meta model. </param>
		/// <param name="EntityName">	Name of the entity. </param>
		/// <param name="ColumnName">	Name of the column. </param>
		///
		/// <returns>	The meta column. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static SWD.MetaColumn GetMetaColumn(this SWD.MetaModel MetaModel, Type EntityName, string ColumnName) {
			return MetaModel.GetMetaColumn(EntityName, ColumnName, false);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A SWD.MetaModel extension method that gets a meta column. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <exception cref="NoColumnException">	Thrown when nocolumn. </exception>
		///
		/// <param name="MetaModel">	The meta model. </param>
		/// <param name="EntityName">	Name of the entity. </param>
		/// <param name="ColumnName">	Name of the column. </param>
		/// <param name="ThrowError">	true to throw error. </param>
		///
		/// <returns>	The meta column. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static SWD.MetaColumn GetMetaColumn(this SWD.MetaModel MetaModel, Type EntityName, string ColumnName, bool ThrowError) {
			var column = MetaModel.GetTable(EntityName).Columns.SingleOrDefault(c => c.Name.ToLower() == ColumnName.ToLower());
			if (column == null && ThrowError) throw new NoColumnException(EntityName.Name, ColumnName);
			return column;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A SWD.MetaModel extension method that gets a meta column. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <exception cref="NoColumnException">	Thrown when nocolumn. </exception>
		///
		/// <param name="MetaModel">	The meta model. </param>
		/// <param name="EntityName">	Name of the entity. </param>
		/// <param name="ColumnName">	Name of the column. </param>
		/// <param name="ThrowError">	true to throw error. </param>
		///
		/// <returns>	The meta column. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static SWD.MetaColumn GetMetaColumn(this SWD.MetaModel MetaModel, string EntityName, string ColumnName, bool ThrowError) {
			var column = MetaModel.GetMetaTable(EntityName, ThrowError).Columns.SingleOrDefault(c => c.Name.ToLower() == ColumnName.ToLower());
			if (column == null && ThrowError) throw new NoColumnException(EntityName, ColumnName);
			return column;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A SWD.MetaModel extension method that gets a meta table. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="MetaModel">	The meta model. </param>
		/// <param name="EntityName">	Name of the entity. </param>
		/// <param name="ThrowError">	true to throw error. </param>
		///
		/// <returns>	The meta table. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static SWD.MetaTable GetMetaTable(this SWD.MetaModel MetaModel, string EntityName, bool ThrowError) {
			return MetaModel.GetTable(MetaModel.GetEntityType(EntityName, ThrowError));
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A SWD.MetaModel extension method that gets an entity type. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <exception cref="TypeLoadException">	Thrown when typeload. </exception>
		///
		/// <param name="MetaModel">	The meta model. </param>
		/// <param name="EntityName">	Name of the entity. </param>
		/// <param name="ThrowError">	true to throw error. </param>
		///
		/// <returns>	The entity type. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static Type GetEntityType(this SWD.MetaModel MetaModel, string EntityName, bool ThrowError) {
			Type type = EntityName.Contains(".") ? Type.GetType(EntityName, true, true) :
				MetaModel.Tables.Where(t => t.EntityType.Name.ToLower() == EntityName.ToLower()).Select(t => t.EntityType).SingleOrDefault();
			if (type == null && ThrowError)
				throw new TypeLoadException("There is no entity of type [" + MetaModel.Tables[0].EntityType.GetBaseName() + "." + EntityName + "].");
			return type;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A SWD.MetaModel extension method that searches for the first action table type. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <typeparam name="TAttribute1">	Type of the attribute 1. </typeparam>
		/// <typeparam name="TAttribute2">	Type of the attribute 2. </typeparam>
		/// <typeparam name="TAttribute3">	Type of the attribute 3. </typeparam>
		/// <param name="MetaModel">			The meta model. </param>
		/// <param name="EntityName">			Name of the entity. </param>
		/// <param name="SelfAsDefault">	true to self as default. </param>
		///
		/// <returns>	The found action table type< t attribute 1, t attribute 2, t attribute 3> </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		private static Type FindActionTableType<TAttribute1, TAttribute2, TAttribute3>(this SWD.MetaModel MetaModel, string EntityName, bool SelfAsDefault)
			where TAttribute1 : ActionTableAttribute
			where TAttribute2 : ActionTableAttribute
			where TAttribute3 : ActionTableAttribute {
			return MetaModel.GetActionTableType<TAttribute1>(EntityName, false) ??
							MetaModel.GetActionTableType<TAttribute2>(EntityName, false) ??
							MetaModel.GetActionTableType<TAttribute3>(EntityName, SelfAsDefault);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A SWD.MetaModel extension method that gets an action table type. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <typeparam name="TAttribute">	Type of the attribute. </typeparam>
		/// <param name="MetaModel">			The meta model. </param>
		/// <param name="EntityName">			Name of the entity. </param>
		/// <param name="SelfAsDefault">	true to self as default. </param>
		///
		/// <returns>	The action table type< t attribute> </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		private static Type GetActionTableType<TAttribute>(this SWD.MetaModel MetaModel, string EntityName, bool SelfAsDefault) where TAttribute : ActionTableAttribute {
			Type entityType = GetEntityType(MetaModel, EntityName, true);
			return MetaModel.GetTable(entityType).Attributes.OfType<TAttribute>()
				.Select(s => s.TableType).SingleOrDefault() ?? (SelfAsDefault ? entityType : null);
		}
		#endregion

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A Table<T> extension method that from identifier. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <typeparam name="T">	Generic type parameter. </typeparam>
		/// <param name="table">	The table to act on. </param>
		/// <param name="id1">		The first identifier. </param>
		/// <param name="id2">		The second identifier. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static T FromId<T>(this Table<T> table, object id1, object id2) where T : class {
			// Get type from Mapping
			MetaType type = table.Context.Mapping.GetTable(typeof(T)).RowType;
			// Only supports 1 ID member            
			MetaDataMember idMember = type.IdentityMembers[0];
			// Build linq query and return result
			ParameterExpression parameter1 = Expression.Parameter(typeof(T), "item");
			var expression = Expression.Lambda<Func<T, bool>>(
				Expression.Equal(Expression.Property(parameter1, idMember.Member.Name), Expression.Constant(id1))
				, parameter1);
			return table.FirstOrDefault(expression);
		}

		#region Get(Data/Table)Set <Generic>

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A Table<TEntity> extension method that gets a data set. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <typeparam name="TEntity">	Type of the entity. </typeparam>
		/// <param name="table">		The table to act on. </param>
		/// <param name="compare">	The compare. </param>
		///
		/// <returns>	The data set< t entity> </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static DataSet GetDataSet<TEntity>(this Table<TEntity> table, Expression<Func<TEntity, bool>> compare) where TEntity : class {
			return GetDataSet<TEntity>(table, compare, "");
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A Table<TEntity> extension method that gets a data set. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <typeparam name="TEntity">	Type of the entity. </typeparam>
		/// <param name="table">			The table to act on. </param>
		/// <param name="compare">		The compare. </param>
		/// <param name="TableName">	Name of the table. </param>
		///
		/// <returns>	The data set< t entity> </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static DataSet GetDataSet<TEntity>(this Table<TEntity> table, Expression<Func<TEntity, bool>> compare, string TableName) where TEntity : class {
			return GetDataSet<TEntity>(table, compare, new DataSet(), TableName);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A Table<TEntity> extension method that gets a data set. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <typeparam name="TEntity">	Type of the entity. </typeparam>
		/// <param name="table">			The table to act on. </param>
		/// <param name="compare">		The compare. </param>
		/// <param name="DS">					The ds. </param>
		/// <param name="TableName">	Name of the table. </param>
		///
		/// <returns>	The data set< t entity> </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static DataSet GetDataSet<TEntity>(this Table<TEntity> table, Expression<Func<TEntity, bool>> compare, DataSet DS, string TableName) where TEntity : class {
			DS.Tables.Add(GetDataTable<TEntity>(table, compare, TableName));
			return DS;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A Table<TEntity> extension method that gets a data table. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <typeparam name="TEntity">	Type of the entity. </typeparam>
		/// <param name="table">		The table to act on. </param>
		/// <param name="compare">	The compare. </param>
		///
		/// <returns>	The data table< t entity> </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static DataTable GetDataTable<TEntity>(this Table<TEntity> table, Expression<Func<TEntity, bool>> compare) where TEntity : class {
			return GetDataTable<TEntity>(table, compare, "");
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A Table<TEntity> extension method that gets a data table. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <typeparam name="TEntity">	Type of the entity. </typeparam>
		/// <param name="table">					The table to act on. </param>
		/// <param name="compare">				The compare. </param>
		/// <param name="DataTableName">	Name of the data table. </param>
		///
		/// <returns>	The data table< t entity> </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static DataTable GetDataTable<TEntity>(this Table<TEntity> table, Expression<Func<TEntity, bool>> compare, string DataTableName) where TEntity : class {
			if (DataTableName + "" == "") DataTableName = table.Context.Mapping.GetTable(typeof(TEntity)).TableName;
			DataTable dt = new DataTable(DataTableName);
			new SqlDataAdapter(table.Context.GetCommand(table.Where(compare)) as SqlCommand).Fill(dt);
			return dt;
		}
		/*
		public static DataSet GetDataSet<TEntity>(this IQueryable<TEntity> query, DataContext Context) where TEntity : class {
			return GetDataSet(query, Context, new DataSet());
		}
		public static DataSet GetDataSet<TEntity>(this IQueryable<TEntity> query, DataContext Context, DataSet DataSet) where TEntity : class {
			return GetDataSet(query, Context, DataSet, "");
		}
		public static DataSet GetDataSet<TEntity>(this IQueryable<TEntity> query, DataContext Context, string DataTableName) where TEntity : class {
			return GetDataSet(query, Context, new DataSet(), DataTableName);
		}
		public static DataSet GetDataSet<TEntity>(this IQueryable<TEntity> query, DataContext Context, DataSet DataSet, string DataTableName) where TEntity : class {
			if (DataSet == null) DataSet = new DataSet();
			DataSet.Tables.Add(GetDataTable(query, Context, DataTableName));
			return DataSet;
		}
		public static DataTable GetDataTable<TEntity>(this IQueryable<TEntity> query, DataContext Context) where TEntity : class {
			return GetDataTable<TEntity>(query, Context, "");
		}
		public static DataTable GetDataTable<TEntity>(this IQueryable<TEntity> query, DataContext Context, string DataTableName) where TEntity : class {
			if (DataTableName + "" == "") DataTableName = Context.Mapping.GetTable(query.ElementType).TableName;
			DataTable dt = new DataTable(DataTableName);
			new SqlDataAdapter(Context.GetCommand(query) as SqlCommand).Fill(dt);
			return dt;
		}
		 * */
		#endregion

		#region Get(Data/Table)Set <Custom>

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A Table<t_LoanInfo_Snapshot> extension method that gets a data set. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="table">		The table to act on. </param>
		/// <param name="DataSet">	Set the data belongs to. </param>
		/// <param name="LoanID">		Identifier for the loan. </param>
		///
		/// <returns>	The data set. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static DataSet GetDataSet(this Table<t_LoanInfo_Snapshot> table, DataSet DataSet, int LoanID) {
			return GetDataSet<t_LoanInfo_Snapshot>(table, s => s.LoanID == LoanID, DataSet, "");
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A Table<t_LoanInfo_Snapshot> extension method that gets a data set. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="table">				The table to act on. </param>
		/// <param name="DataSet">			Set the data belongs to. </param>
		/// <param name="LoanID">				Identifier for the loan. </param>
		/// <param name="SnapshotName">	Name of the snapshot. </param>
		///
		/// <returns>	The data set. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static DataSet GetDataSet(this Table<v_TruthInLending_Snapshot> table, DataSet DataSet, int LoanID, string SnapshotName) {
			return GetDataSet<v_TruthInLending_Snapshot>(table, s => s.LoanID == LoanID && new[] { s.SnapshotName, "" }.Contains(SnapshotName), DataSet, "");
		}
		#endregion

		#region Fill Table

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A DataRow extension method that converts a dataRow to a table entity. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <exception cref="DataRowToTableEntityException">	Thrown when datarowtotableentity. </exception>
		///
		/// <typeparam name="TEntity">	Type of the entity. </typeparam>
		/// <param name="dataRow">	The dataRow to act on. </param>
		///
		/// <returns>	This object as a TEntity. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static TEntity ToTableEntity<TEntity>(this DataRow dataRow) where TEntity : class {
			var item = Activator.CreateInstance<TEntity>();
			foreach (DataColumn col in dataRow.Table.Columns) {
				try {
					if (!dataRow.IsNull(col)) {
						item.SetProperty(item.FindTableEntityProperty(col.ColumnName), dataRow[col]);
						//typeof(TEntity).GetProperty(item.FindTableEntityProperty(col.ColumnName)).SetValue(item, dataRow[col], null);
					}
				} catch (Exception exc) { throw new DataRowToTableEntityException(col.ColumnName, exc); }
			}
			return item;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Exception for signalling data row to table entity errors. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public class DataRowToTableEntityException : Exception {
			public string ColumnName { get; private set; }
			public DataRowToTableEntityException(string ColumnName, Exception exc) :
				base("Column [" + ColumnName + "] can not be imported.", exc) {
				this.ColumnName = ColumnName;
			}
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Enumerates to i enumerable in this collection. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <typeparam name="TEntity">	Type of the entity. </typeparam>
		/// <param name="dataTable">	The dataTable to act on. </param>
		///
		/// <returns>	
		/// An enumerator that allows foreach to be used to process to i enumerable< t entity> in this
		/// collection. 
		/// </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static IEnumerable<TEntity> ToIEnumerable<TEntity>(this DataTable dataTable) where TEntity : class {
			return dataTable.Rows.OfType<DataRow>().Select<DataRow, TEntity>(s => s.ToTableEntity<TEntity>());
		}
		// public static void Fill<TEntity>(this Table<TEntity> table, DataTable dataTable) where
		// TEntity : class {
		//   var items = dataTable.Rows.OfType<DataRow>().Select<DataRow, TEntity>(s =>
		//   s.ToTableEntity<TEntity>());
		//   table.InsertAllOnSubmit<TEntity>(items);
		// }
		// public static void Fill<TEntity>(this Table<TEntity> table, DataRow dataRow) where TEntity :
		// class {
		//   var item = Activator.CreateInstance<TEntity>();
		//   foreach (DataColumn col in dataRow.Table.Columns) {
		//     typeof(TEntity).GetProperty(item.FindTableEntityProperty(col.ColumnName)).SetValue(item,
		//     dataRow[col], null);
		//   }
		//   table.InsertOnSubmit(item);
		// } 
		#endregion

		#region toDataTable
		static string FindTableEntityProperty<TEntity>(this TEntity item, string columnName) where TEntity : class {
			foreach (var property in typeof(TEntity).GetProperties()) {
				if (property.Name.ToLower() == columnName.ToLower()) return property.Name;
				var columnAttribute = property.GetCustomAttributes(typeof(ColumnAttribute), true).Cast<ColumnAttribute>().Select(s => s.Name).SingleOrDefault() + "";
				if (StringComparer.CurrentCultureIgnoreCase.Compare(Regex.Match(columnAttribute, "^\\[?(.+?)\\]?$").Groups[1].Value.ToLower(), columnName.ToLower()) == 0) return property.Name;
			}
			throw new NotImplementedException("Property [" + columnName + "] is not implemented in " + typeof(TEntity).Name);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Converts a name to a data table. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <typeparam name="T">	Generic type parameter. </typeparam>
		/// <param name="name">	The name. </param>
		///
		/// <returns>	This object as a DataTable. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static DataTable ToDataTable<T>(string name) where T : class {
			DataTable dt = new DataTable();
			foreach (var property in typeof(T).GetProperties()) {
				if (property.PropertyType.GetCustomAttributes(typeof(TableAttribute), true).Length == 0) {
					Type t = Nullable.GetUnderlyingType(property.PropertyType);
					var columnAttribute = property.GetCustomAttributes(typeof(ColumnAttribute), true).Cast<ColumnAttribute>().Select(s => s.Name).SingleOrDefault() + "";
					string columnName = columnAttribute == "" ? property.Name : Regex.Match(columnAttribute, "^\\[?(.+?)\\]?$").Groups[1].Value;
					dt.Columns.Add(columnName, t == null ? property.PropertyType : t);
				}
			}
			return dt;
		}
		#endregion

		#region ToXML

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	An IEnumerable<T> extension method that converts the items to an xml. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <typeparam name="T">	Generic type parameter. </typeparam>
		/// <param name="items">	The items to act on. </param>
		///
		/// <returns>	This object as an XElement. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static XElement ToXML<T>(this IEnumerable<T> items) where T : class {
			string name = typeof(T).GetCustomAttributes(typeof(TableAttribute), true).Cast<TableAttribute>().Select(s => s.Name).FirstOrDefault();
			if (name + "" == "") name = "R";
			return ToXML<T>(items, name);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	An IEnumerable<T> extension method that converts the items to an xml. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <typeparam name="T">	Generic type parameter. </typeparam>
		/// <param name="items">	The items to act on. </param>
		/// <param name="name">		The name. </param>
		///
		/// <returns>	This object as an XElement. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static XElement ToXML<T>(this IEnumerable<T> items, string name) where T : class {
			var tableTypes = MotoBank.MetaModel.Tables.Select(t => t.EntityType);
			XElement xml = new XElement(name + "s");
			foreach (T item in items) {
				XElement xValues = new XElement(name);
				foreach (PropertyInfo property in typeof(T).GetProperties()) {
					if (tableTypes.Contains(property.PropertyType)) continue;
					var obj = property.GetValue(item, null);
					xValues.SetAttributeValue(property.Name, obj + "");
				}
				xml.Add(xValues);
			}
			return xml;
		}
		#endregion

		#region SELECT/UPDATE/DELETE/INSERT
		#region Delete <Generic>

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A Table<T> extension method that deletes this object. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <exception cref="Exception">	Thrown when exception. </exception>
		///
		/// <typeparam name="T">	Generic type parameter. </typeparam>
		/// <param name="table">		The table to act on. </param>
		/// <param name="compare">	The compare. </param>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static void Delete<T>(this Table<T> table, Expression<Func<T, bool>> compare) where T : class {
			try {
				var rec = table.Where(compare);
				table.DeleteAllOnSubmit(rec);
				table.Context.SubmitChanges(ConflictMode.FailOnFirstConflict);
			} catch (Exception exc) {
				exc.Data["EntityType"] = typeof(T).Name;
				Dimok.Exceptions.ASPException.Publish(exc);
				throw exc;
			}
		}
		#endregion

		#region Update <Dynamic>

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	An ITable extension method that updates this object. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <exception cref="NoTableException">				Thrown when notable. </exception>
		/// <exception cref="Exception">							Thrown when exception. </exception>
		/// <exception cref="NotSupportedException">	Thrown when the requested operation is not supported. </exception>
		///
		/// <param name="table">				The table to act on. </param>
		/// <param name="filter">				The filter. </param>
		/// <param name="filterValues">	The filter values. </param>
		/// <param name="fields">				The fields. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static IQueryable Update(this ITable table, string filter, object[] filterValues, Dictionary<string, object> fields) {
			if (table == null) throw new NoTableException();
			var OldValues = table.Where(filter, filterValues);
			if (OldValues.Count() == 0) throw new Exception("No records found for " + filter);
			if (OldValues.Count() > 1) throw new NotSupportedException("Update of multiple records is no supported.");
			LinqDataSource linqDS = new LinqDataSource() { EnableUpdate = true };
			linqDS.ContextTypeName = table.Context.GetType().FullName;
			linqDS.TableName = table.Context.GetType().GetProperties().
				Cast<PropertyInfo>().Single(p => p.PropertyType.FullName.Contains(table.ElementType.FullName + ",")).Name;
			object item = OldValues.Cast<object>().Single();
			Dictionary<string, object> ov = TypeDescriptor.GetProperties(item).Cast<PropertyDescriptor>().
					Where(p => p.Attributes[typeof(ColumnAttribute)] != null).ToDictionary(p => p.Name, p => p.GetValue(item));
			linqDS.Update(null, fields, ov);
			return table.Select(filter, filterValues);
		}

		#endregion

		#region Update <Generic>

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A Table<T> extension method that updates this object. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <exception cref="NotSupportedException">	Thrown when the requested operation is not supported. </exception>
		///
		/// <typeparam name="T">	Generic type parameter. </typeparam>
		/// <param name="table">					The table to act on. </param>
		/// <param name="compare">				The compare. </param>
		/// <param name="NewNameValues">	The new name values. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static IQueryable<T> Update<T>(this Table<T> table, Expression<Func<T, bool>> compare, Dictionary<string,object> NewNameValues) where T : class {
			IQueryable OldValues = table.Where(compare);
			if (OldValues.Count() > 1) throw new NotSupportedException("Update of multiple records is no supported.");
			ListDictionary NewValues = new ListDictionary();
			LinqDataSource linqDS = new LinqDataSource();
			linqDS.EnableUpdate = true;
			linqDS.ContextTypeName = typeof(MotoBank).ToString();
			linqDS.TableName = table.Context.GetType().GetProperties().
				Cast<PropertyInfo>().Single(p => p.PropertyType.FullName.Contains(((ITable)table).ElementType.FullName + ",")).Name;
			ListDictionary ldOld = new ListDictionary();
			foreach (object item in OldValues) {
				PropertyDescriptorCollection originalProps = TypeDescriptor.GetProperties(item);
				foreach (PropertyDescriptor currentProp in originalProps) {
					if (currentProp.Attributes[typeof(System.Data.Linq.Mapping.ColumnAttribute)] != null) {
						object val = currentProp.GetValue(item);
						ldOld.Add(currentProp.Name, val);
						//if( currentProp.Attributes[typeof(System.Data.Linq.Mapping.c
					}
				}
			}
			linqDS.Update(null, NewNameValues, ldOld);
			var res = table.Where(compare);
			table.Context.Refresh(RefreshMode.OverwriteCurrentValues, res);
			return res;
		}

		#endregion

		#region Update <Custom>

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	An ITable extension method that updates this object. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="table">				The table to act on. </param>
		/// <param name="LoanID">				Identifier for the loan. </param>
		/// <param name="SnapshotName">	Name of the snapshot. </param>
		/// <param name="NameValues">		The name values. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static IQueryable<v_TruthInLending_Snapshot> Update(this Table<v_TruthInLending_Snapshot> table, int LoanID, string SnapshotName, object NameValues) {
			return Update(table, LoanID , SnapshotName, NameValues.ToDictionary());
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	An ITable extension method that updates this object. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="table">				The table to act on. </param>
		/// <param name="LoanID">				Identifier for the loan. </param>
		/// <param name="SnapshotName">	Name of the snapshot. </param>
		/// <param name="NameValues">		The name values. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static IQueryable<v_TruthInLending_Snapshot> Update(this Table<v_TruthInLending_Snapshot> table, int LoanID, string SnapshotName, Dictionary<string,object> NameValues) {
			return Update(table, s => s.LoanID == LoanID && s.SnapshotName == SnapshotName, NameValues);
		}
		#endregion

		#region Insert <Generic>
		// public static TableView<TEntity> Insert<TEntity>(this Table<TEntity> table, params
		// NameValue[] NameValues) where TEntity : class {
		//   return Insert<TEntity>(table, NameValues.ToDictionary(s => s.Name, s => s.Value));
		// } 
		public static IEnumerable Insert(this ITable table, object insertDataObject) {
			return table.Insert(insertDataObject.ToDictionary());
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	An ITable extension method that inserts. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <exception cref="Exception">	Thrown when exception. </exception>
		///
		/// <param name="table">	The table to act on. </param>
		/// <param name="Values">	The values. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static IQueryable Insert(this ITable table, Dictionary<string, object> Values) {
			string tableName = table.Context.Mapping.GetTable(table.ElementType).TableName;
			string sqlInsert = "INSERT INTO " + tableName + "(" + string.Join(",", Values.Keys.ToArray()) + ")";
			sqlInsert += "VALUES(";
			List<string> insertParams = new List<string>();
			List<string> selectParams = new List<string>();
			for (var i = 0; i < Values.Count; i++) {
				insertParams.Add("{" + i + "}");
				selectParams.Add(Values.Keys.ToArray()[i] + "={" + i + "}");
			}
			sqlInsert += string.Join(",", insertParams.ToArray()) + ")";
			if (table.ElementType.GetProperties().Select(p => p.Name).Contains("ID"))
				sqlInsert += "SELECT * FROM " + tableName + " WHERE SCOPE_IDENTITY() = ID";
			else sqlInsert += "SELECT SCOPE_IDENTITY() ID";

			string sqlSelect = "SELECT * FROM " + tableName + " WHERE " + string.Join(" AND ", selectParams.ToArray());
			try {
				var ret = table.Context.ExecuteQuery(table.ElementType, sqlInsert, Values.Values.ToArray());
				return ret.AsQueryable();
			} catch (Exception exc) {
				exc.Data["SQL"] = sqlInsert;
				throw exc;
			}
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Identity. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		private class Identity {
			public int ID = 0;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A Table<TEntity> extension method that inserts. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <typeparam name="TEntity">	Type of the entity. </typeparam>
		/// <param name="table">	The table to act on. </param>
		/// <param name="dic">		The dic. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static TableView<TEntity> Insert<TEntity>(this Table<TEntity> table, Dictionary<string, object> dic) where TEntity : class {
			string tableName = table.Context.Mapping.GetTable(typeof(TEntity)).TableName;
			string sqlInsert = "INSERT INTO " + tableName + "(" + string.Join(",", dic.Keys.ToArray()) + ")";
			sqlInsert += "VALUES(";
			List<string> insertParams = new List<string>();
			List<string> selectParams = new List<string>();
			for (var i = 0; i < dic.Count; i++) {
				insertParams.Add("{" + i + "}");
				selectParams.Add(dic.Keys.ToArray()[i] + "={" + i + "}");
			}
			sqlInsert += string.Join(",", insertParams.ToArray()) + ")";

			string sqlSelect = "SELECT * FROM " + tableName + " WHERE " + string.Join(" AND ", selectParams.ToArray());
			return new TableView<TEntity>(table, table.Context.ExecuteQuery<TEntity>(sqlInsert + sqlSelect, dic.Values.ToArray()).AsQueryable());
			//var lds = new LinqDataSource();
			//lds.EnableInsert = true;
			//lds.ContextTypeName = table.Context.GetType().ToString();
			//lds.TableName = ((MotoBankDataContext)table.Context).GetEntityTableName<TEntity>();
			//lds.Inserted += new EventHandler<LinqDataSourceStatusEventArgs>(lds_Inserted);
			//lds.Insert(dic);
			//return null;
		}


		#endregion

		#region Select <Generic>
		// public static TableView<TEntity> Select<TEntity>(this Table<TEntity> table,
		// Expression<Func<TEntity, bool>> compare) where TEntity : class {
		//   var t = table.Where(compare);
		//   //select s;
		//   return new TableView<TEntity>(table, t);
		// } 
		#endregion

		#region Select <Custom>
		public static TableView<v_TruthInLending_Snapshot> Select(this Table<v_TruthInLending_Snapshot> table, int LoanID, string SnapshotName) {
			return new TableView<v_TruthInLending_Snapshot>(table, table.Where(s => s.LoanID == LoanID && s.SnapshotName == SnapshotName));
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	A Table<v_TruthInLending_Snapshot> extension method that selects. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="table">	The table to act on. </param>
		/// <param name="LoanID">	Identifier for the loan. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static TableView<v_TruthInLending_Snapshot> Select(this Table<v_TruthInLending_Snapshot> table, int LoanID) {
			return new TableView<v_TruthInLending_Snapshot>(table, table.Where(s => s.LoanID == LoanID));
		}
		#endregion
		#endregion

	}
	#endregion
}